import {
  batchSaveModules,
  exportCanvasJson,
  getCanvasFonts,
  getCanvasPageModules,
  getCanvasPages,
  graphInfo
} from '@/api/graph.js'
import { MiniMap } from '@/components/x6-plugin-minimap/index.js'
import { FIELDS_PATH } from '@/config/index.js'
import { ColorEnum } from '@/enum/graph.enum.js'
import { getSense } from '@/utils/dict.js'
import { getSize, serializeRequestForm } from '@/utils/index.js'
import {
  getNodeListForModules,
  getTransferNodeConfig
} from '@/utils/transferNodeConfig.js'
import { Graph } from '@antv/x6'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { Export } from '@antv/x6-plugin-export'
import { History } from '@antv/x6-plugin-history'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Transform } from '@antv/x6-plugin-transform'
import { Message } from '@arco-design/web-vue'
import { LoadingFour } from '@icon-park/vue-next'
import { saveAs } from 'file-saver'
import { defineStore } from 'pinia'
import { h, reactive } from 'vue'

const miniMapScale = 0.3
export const useGraphStore = defineStore(
  'graphStore',
  () => {
    let graphEditor = null
    const graph = reactive({
      nodeConfigForm: {}, // 选中节点 form
      activePageId: null,
      pageList: [],
      // 详情
      info: {
        width: 800,
        height: 400,
        color: 'black_white_red',
        backgroundColor: 'white',
        id: null,
        canvasKey: null,
        name: null,
        overlapRule: '2',
        size: '320×240',
        sizeType: '2.4',
        fontList: []
      },
      // 选中节点id
      selectNode: null,
      // 缩放倍数
      scaleCount: 1,
      // 当前画布节点列表
      nodeList: []
    })
    const initCanvas = async ({ width = 800, height = 400, element }) => {
      const bgColor = ColorEnum[graph.info.backgroundColor].color || '#ffffff'
      graphEditor = new Graph({
        container: element,
        width,
        height,
        panning: false,
        mousewheel: false,
        grid: {
          visible: false
        },
        background: {
          color: bgColor
        },
        translating: {
          restrict: true
        },
        interacting: {
          nodeMovable (view) {
            const node = view.cell
            const { _isEnableMove } = node.getData()
            return _isEnableMove
          }
        }
      })
      initPlugins(graphEditor)
      initKeyboard(graphEditor)
      initEvents(graphEditor)
      return graphEditor
    }
    /**
     * 初始化插件
     * @param graphEditor
     */
    const initPlugins = (graphEditor) => {
      const { width, height } = graph.info
      // 对齐线
      graphEditor.use(
        new Snapline({
          enabled: true
        })
      )
      graphEditor.use(new Export())
      // 快捷键
      graphEditor.use(
        new Keyboard({
          enabled: true
        })
      )
      // 复制粘贴
      graphEditor.use(
        new Clipboard({
          enabled: true
        })
      )
      // 框选
      graphEditor.use(
        new Selection({
          enabled: true,
          multiple: false,
          rubberband: true,
          movable: true,
          showNodeSelectionBox: true
        })
      )
      // 撤销重做
      graphEditor.use(
        new History({
          enabled: true
        })
      )
      // 图形变换
      graphEditor.use(
        new Transform({
          resizing: {
            enabled: true,
            minWidth: 1,
            maxWidth: width,
            minHeight: 1,
            allowReverse: false,
            maxHeight: height,
            preserveAspectRatio (node) {
              const { _isPreserveAspectRatio } = node.getData()
              return _isPreserveAspectRatio || false
            }
          },
          rotating: {
            enabled: true,
            grid: 5
          }
        })
      )
      graphEditor.use(
        new MiniMap({
          container: document.querySelector('#editor-minimap-content'),
          width: width * miniMapScale,
          height: height * miniMapScale,
          padding: 0,
          graphOptions: {
            scaling: {
              min: miniMapScale,
              max: miniMapScale
            }
          }
        })
      )
    }
    /**
     * 初始化快捷键
     * @param graphEditor 实例
     */
    const initKeyboard = (graphEditor) => {
      // 复制
      graphEditor.bindKey(['meta+c', 'ctrl+c'], copyNodes)
      graphEditor.bindKey(['meta+v', 'ctrl+v'], pasteNodes)
      // delete
      graphEditor.bindKey('backspace', delNodes)

      // undo redo
      graphEditor.bindKey(['meta+z', 'ctrl+z'], () => {
        if (graphEditor.canUndo()) {
          graphEditor.undo()
        }
        return false
      })
    }
    /**
     * 初始化绑定事件
     * @param graphEditor
     */
    const initEvents = (graphEditor) => {
      const onChangeNodeList = () => {
        graph.nodeList = graphEditor.getNodes()
      }
      graphEditor.on('node:added', (cell) => {
        // 6-21增加放置次序的字段
        const nodes = graphEditor.getNodes()
        const maxSetIndex = Math.max(
          ...nodes.map((node) => {
            const data = node.getData()
            return data.setIndex || 0
          })
        )
        cell.node.setData(
          { ...cell.node.getData(), setIndex: maxSetIndex + 1 },
          { silent: true }
        )
        onChangeNodeList()
      })
      graphEditor.on('node:removed', onChangeNodeList)

      // 需要改变数据层
      graphEditor.on('node:resized', ({ node }) => {
        const { width, height } = node.size()
        onChangeNodeAttr({
          width: Math.round(width),
          height: Math.round(height)
        })
      })
      graphEditor.on('node:rotated', ({ node }) => {
        const rotate = node.getAngle()
        onChangeNodeAttr({
          rotate: Math.round(rotate)
        })
      })
      graphEditor.on('node:moved', ({ node }) => {
        const { x, y } = node.position()
        onChangeNodeAttr({
          startX: Math.round(x),
          startY: Math.round(y)
        })
      })
      graphEditor.on('node:click', ({ node }) => {
        console.log('click', node)
        onChangeSelectNode({
          id: node.id,
          isNeedSelect: false
        })
      })

      graphEditor.on('blank:click', () => {
        console.log('blank:click')
        graphEditor.resetSelection()
        onChangeSelectNode({})
      })
    }
    /**
     * 根据配置添加节点
     * @param nodeConfig
     */
    const addNode = (nodeConfig) => {
      const node = {
        ...nodeConfig,
        width: nodeConfig.data.width,
        height: nodeConfig.data.height,
        x: nodeConfig.data.startX,
        y: nodeConfig.data.startY
      }
      if (Object.prototype.hasOwnProperty.call(node.data, 'fontType')) {
        const defaultFontType = graph.info.fontList.find(
          (item) => item.isDefault === '1'
        )
        console.log(defaultFontType)
        if (defaultFontType) {
          node.data.fontType = node.data.fontType || defaultFontType.fontName
        }
      }
      console.log(node)
      // 添加节点时将画布所有节点禁止移动
      const addNode = graphEditor.addNode(node)
      graphEditor.clearTransformWidgets()
      onChangeSelectNode({
        id: addNode.id,
        isNeedSelect: true
      })
    }
    /**
     * 撤回
     */
    const undoGraph = () => {
      graphEditor.undo()
    }
    /**
     * 重做
     */
    const redoGraph = () => {
      graphEditor.redo()
    }
    /**
     * 导出画布
     * @return {Promise<void>}
     */
    const exportToGraph = async () => {
      const res = await exportCanvasJson(graph.info.id)
      const blob = new Blob([res], { type: 'application/octet-stream' })
      saveAs(blob, `${graph.info.name}.zip`)
      Message.success('导出JSON成功')
    }
    /**
     * 复制所选节点
     */
    const copyNodes = () => {
      const cells = graphEditor.getSelectedCells()
      if (cells && cells.length) {
        graphEditor.copy(cells)
      } else {
        Message.warning('请先选中节点再复制')
      }
    }
    /**
     * 粘贴剪切板节点
     */
    const pasteNodes = () => {
      if (graphEditor.isClipboardEmpty()) {
        Message.warning('剪切板为空，不可粘贴')
      } else {
        const node = graphEditor.paste()
        graphEditor.cleanSelection()
        graphEditor.clearTransformWidgets()
        onChangeSelectNode({
          id: node.id,
          isNeedSelect: true
        })
      }
    }
    /**
     * 设置元素在画布的对齐位置
     * @param position
     */
    const setAlignMode = (position) => {
      const cells = graphEditor.getSelectedCells()
      const { width, height } = graph.info
      if (cells && cells.length) {
        cells.forEach((cell) => {
          const size = cell.size()
          switch (position) {
            case 'left':
              cell.prop('position/x', 0)
              onChangeNodeAttr({ start_x: 0 })
              break
            case 'horizontally':
              cell.prop('position/x', width / 2 - size.width / 2)
              onChangeNodeAttr({ start_x: width / 2 - size.width / 2 })
              break
            case 'right':
              cell.prop('position/x', width - size.width)
              onChangeNodeAttr({ start_x: width - size.width })
              break
            case 'top':
              cell.prop('position/y', 0)
              onChangeNodeAttr({ start_y: 0 })
              break
            case 'vertically':
              cell.prop('position/y', height / 2 - size.height / 2)
              onChangeNodeAttr({ start_y: height / 2 - size.height / 2 })
              break
            case 'bottom':
              cell.prop('position/y', height - size.height)
              onChangeNodeAttr({ start_y: height - size.height })
              break
          }
        })
      }
    }
    /**
     * 清空选中节点
     */
    const clearSelectNode = () => {
      graph.nodeConfigForm = {}
      graph.selectNode = null
    }
    /**
     * 删除所选节点
     */
    const delNodes = () => {
      const cells = graphEditor.getSelectedCells()
      if (cells && cells.length) {
        graphEditor.removeCells(cells)
        // 删除节点时如果配置面板打开是需要进行判断
        if (graph.selectNode) {
          const ids = cells.map((c) => c.id)
          if (ids.includes(graph.selectNode.id)) {
            clearSelectNode()
          }
        }
      }
    }
    /**
     * 清空画布
     */
    const clearGraph = () => {
      graphEditor.clearCells()
      clearSelectNode()
    }
    /**
     * 修改当前选中节点
     * @param id 节点 id
     * @param isNeedSelect 是否需要框选
     */
    const onChangeSelectNode = ({ id, isNeedSelect = false }) => {
      // 选中节点时将页面所有节点禁止移动
      const nodes = graphEditor.getNodes()
      nodes.forEach((node) => {
        node.setData({
          _isEnableMove: false
        })
      })
      if (!id) {
        clearSelectNode()
      } else {
        const node = graphEditor.getCellById(id)
        if (isNeedSelect) {
          graphEditor.createTransformWidget(node)
          graphEditor.resetSelection(node)
        }
        node.setData({
          _isEnableMove: true
        })
        node.toFront()
        graph.selectNode = node
        graph.nodeConfigForm = getTransferNodeConfig(graph.selectNode)
      }
    }
    /**
     * 修改节点的属性,需要更新选中节点的属性
     * @param newData
     */
    const onChangeNodeAttr = (newData) => {
      if (!graph.selectNode) return false
      const nodeData = graph.selectNode?.getData()
      const basicAttributes = ['startX', 'startY', 'width', 'height', 'rotate']
      for (const key in newData) {
        graph.nodeConfigForm[key] = newData[key]
        // 上述属性不属于 data 需要单独修改
        if (basicAttributes.includes(key)) {
          graph.selectNode.prop(FIELDS_PATH[key], newData[key])
        }
      }
      graph.selectNode.setData({
        ...nodeData,
        ...newData
      })
    }
    /**
     * 修改画布缩放倍数
     * @param type
     */
    const onChangeGraphScale = (type) => {
      const step = 0.05
      const minScale = 0.2
      const maxScale = 2
      // 计算新的缩放比例
      const newScale =
        type === 'out' ? graph.scaleCount + step : graph.scaleCount - step

      // 确保新的缩放比例在允许的范围内
      if (newScale >= minScale && newScale <= maxScale) {
        graph.scaleCount = parseFloat(newScale.toFixed(2))
      }
    }
    /**
     * 切换画布页
     * @param page
     * @return {Promise<boolean>}
     */
    const onChangePage = async (page) => {
      try {
        if (!page) return false
        // 保存完再进行清空添加
        // 切换->保存->清空->添加

        if (graphEditor) {
          clearGraph()
        }
        graph.activePageId = page.id
        const { canvasKey, id } = page
        const { data } = await getCanvasPageModules({
          canvasKey,
          pageCode: id
        })
        if (data && data.length) {
          const nodeList = getNodeListForModules(data)
          graphEditor.addNodes(nodeList)
        }
      } catch (e) {
        Message.warning('切换失败')
      }
    }

    /**
     * 获取画布页列表
     * @return {Promise<void>}
     */
    const getPageList = async () => {
      const { data } = await getCanvasPages(graph.info.canvasKey)
      if (data && data.length) {
        graph.pageList = data
      }
    }
    /**
     * 获取画布模板详情
     * @param id
     * @return {Promise<void>}
     */
    const getInfo = async (id) => {
      const { data } = await graphInfo(id)

      if (data) {
        const {
          size,
          backgroundColor,
          id,
          canvasKey,
          overlapRule,
          name,
          color
        } = data
        const { width, height } = getSize(size)
        graph.info.width = width
        graph.info.height = height
        graph.info.backgroundColor = backgroundColor || 'white'
        graph.info.color = color || 'white'
        graph.info.canvasKey = canvasKey
        graph.info.id = id
        graph.info.name = name
        graph.info.size = size
        graph.info.overlapRule = overlapRule
        await getPageList()
        const fontRes = await getCanvasFonts()
        graph.info.fontList = fontRes.data
        window._graphFontList_ = fontRes.data
      }
    }
    /**
     * 保存当前画布页数据
     * @return {Promise<void>}
     */
    const savePage = async () => {
      const saveLoading = Message.warning({
        icon: () => {
          return h(LoadingFour, { spin: true })
        },
        content: '保存中',
        duration: 20000
      })
      const { cells } = graphEditor.toJSON()
      const moduleSense = getSense('IOT_CANVAS_MODULE_TABLE_DEFAULT')

      // 格式化节点数据的辅助函数
      const formatNodeData = (item) => ({
        id: item.id,
        canvasKey: graph.info.canvasKey,
        pageCode: graph.activePageId,
        rankIndex: item.zIndex,
        ...item.data,
        endX: item.data.startX + item.data.width,
        endY: item.data.startY + item.data.height,
        fontBold: item.data.fontBold ? 'bold' : null,
        fontItalic: item.data.fontItalic ? 'italic' : null
      })
      const nodeList = cells.map((item) => formatNodeData(item))
      console.log('保存画布', nodeList)
      console.log(
        '节点顺序',
        nodeList.map((item) => item.setIndex)
      )
      const kvSaveModule = nodeList.map((item) => ({
        senseCode: moduleSense,
        formFields: serializeRequestForm(item)
      }))
      const saveData = {
        mainObject: 'userPostion',
        formCollect: kvSaveModule,
        batchFilter: [{ K: 'pageCode', V: graph.activePageId }]
      }
      await batchSaveModules(saveData)
      saveLoading.close()
      Message.success('保存成功')
    }
    const exportImage = async () => {
      console.log(graph.info)
      graphEditor.exportPNG('file.png', {
        width: graph.info.width,
        height: graph.info.height,
        backgroundColor: graph.info.backgroundColor,
        quality: 1
      })
    }
    const $reset = () => {
      graphEditor = null
      graph.info = {
        width: 800,
        height: 400,
        color: 'black_white_red',
        backgroundColor: 'white',
        id: null,
        canvasKey: null,
        name: null,
        overlapRule: '2',
        size: '320×240',
        sizeType: '2.4',
        fontList: []
      }
      graph.activePageId = null
      graph.selectNode = null
      graph.nodeList = []
      graph.pageList = []
      graph.nodeConfigForm = {}
      graph.scaleCount = 1
    }
    return {
      graph,
      graphEditor,
      exportImage,
      onChangeGraphScale,
      setAlignMode,
      onChangeSelectNode,
      onChangeNodeAttr,
      pasteNodes,
      delNodes,
      copyNodes,
      exportToGraph,
      initCanvas,
      addNode,
      undoGraph,
      redoGraph,
      clearGraph,
      getInfo,
      onChangePage,
      getPageList,
      savePage,
      $reset
    }
  },
  { persist: false }
)
